package com.fauks.ee.full_text_retrieva.lucene;

import org.apache.commons.io.FileUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.*;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.nio.file.Paths;

public class LuceneDemo1 {

    // 创建索引
    @Test
    public void testCreateIndex() throws IOException {
        IndexWriter indexWriter = getIndexWriter();

        //指定field对象，将field对象放到document对象中
        //原始文档路径
        File oriFile = new File("D:\\lucene\\doc");
        File[] files = oriFile.listFiles();
        for (File file : files) {
            Document document = new Document();
            String fileName = file.getName();
            //Field.Store.NO不存储文件名 TextField可选是否存储
            Field fileNameField = new TextField("file_name", fileName, Field.Store.YES);
            document.add(fileNameField);

            long fileSize = FileUtils.sizeOf(file);
            System.out.println("fileSize:" + fileSize);
            Field fileSizeField = new StoredField("file_size", fileSize);
            document.add(fileSizeField);

            String filePath = file.getPath();
            //StoredField必须存储，因为需要通过路径找到文件所以必须要存储
            Field filePathField = new StoredField("file_path", filePath);
            document.add(filePathField);

            String fileContent = FileUtils.readFileToString(file, "utf-8");
            Field fileContentField = new StoredField("file_content", fileContent);
            document.add(fileContentField);
            indexWriter.addDocument(document);
            //将文档对象通过IndexWriter写入索引库，此过程创建索引并将索引与文档对象一同写入索引库
        }
        //关闭流
        indexWriter.close();
    }

    private IndexWriter getIndexWriter() throws IOException {
        //1.创建IndexWriter对象
        //FSDirectory指定索引库存放位置（RAMDirectory内存索引库）
        Directory dir = FSDirectory.open(Paths.get("D:\\lucene\\index"));
        //分词器
        Analyzer analyzer = new StandardAnalyzer(); //标准分词对中文不友好
        IndexWriterConfig conf = new IndexWriterConfig(analyzer);
        return new IndexWriter(dir, conf);
    }

    //查询索引
    @Test
    public void testSearch() throws Exception {
        //指定索引库位置
        Directory directory = FSDirectory.open(Paths.get("D:\\lucene\\index"));
        //创建IndexReader对象
        IndexReader indexReader = DirectoryReader.open(directory);
        //创建查询对象
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);

        //创建TermQuery(精准查询)对象指定查询的域与关键字
        //子类查询-->使用对象查询
        //Query query = new TermQuery(new Term("file_name", "测"));
        //Query query = new MatchAllDocsQuery();//查询所有
        //Query query =PointRangeQuery.checkArgs("file_size",10,200);//根据数值范围查询(例如按照价格范围查询)
        //BooleanQuery ;//组合查询

        //queryParser查询-->使用语法查询
        // *:* 相当于查询全部
        QueryParser queryParser = new QueryParser("file_name", new StandardAnalyzer());
        Query query = queryParser.parse("spring");//可以不指定key使用默认的file_name
        //执行查询 指定返回10条结果
        TopDocs topDocs = indexSearcher.search(query, 10);
        //返回查询结果遍历输出
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        for (ScoreDoc scoreDoc : scoreDocs) {
            int doc = scoreDoc.doc;//返回文档Id
            Document document = indexSearcher.doc(doc);
            String file_name = document.get("file_name");
            System.out.println("文件名称:" + file_name);
            System.out.println("文件路径:" + document.get("file_path"));
            System.out.println("文件大小:" + document.get("file_size"));
            //System.out.println("文件内容:" + document.get("file_content"));

            System.out.println("----------------");
        }

        indexReader.close();
    }

    //查看分词器
    @Test
    public void testTokenStream() throws IOException {
        //IKAnalyzer第三方中文友好分词器
        Analyzer analyzer = null; //new IKAnalyzer(true);

        StringReader stringReader = new StringReader("高富帅可以用二维表结构来逻辑表达实现的数据");
        TokenStream tokenStream = analyzer.tokenStream("",
                stringReader);
        // 添加一个引用，可以获得每个关键词
        CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
        // 添加一个偏移量的引用，记录了关键词的开始位置以及结束位置
        OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
        // 将指针调整到列表的头部
        tokenStream.reset();
        // 遍历关键词列表，通过incrementToken方法判断列表是否结束
        while (tokenStream.incrementToken()) {
            // 关键词的起始位置
            System.out.println("start->" + offsetAttribute.startOffset());
            // 取关键词
            System.out.println(charTermAttribute);
            // 结束位置
            System.out.println("end->" + offsetAttribute.endOffset());
        }
        tokenStream.close();
    }

    //删除所有索引
    @Test
    public void testDeleteAllIndex() throws IOException {
        IndexWriter indexWriter = getIndexWriter();
        indexWriter.deleteAll();
        indexWriter.close();
    }

    //删除指定索引
    @Test
    public void testDeleteIndex() throws IOException {
        IndexWriter indexWriter = getIndexWriter();
        indexWriter.deleteDocuments(new Term("file_name", "apache"));
        indexWriter.close();
    }

    //更新索引：先删除索引再新增索引
    @Test
    public void testUpdateIndex() throws IOException {
        IndexWriter indexWriter = getIndexWriter();
        Document document = new Document();
        document.add(new TextField("file_name", "测试文件名", Field.Store.YES));
        document.add(new TextField("file_name", "测试文件名2", Field.Store.YES));

        indexWriter.updateDocument(new Term("file_name", "apache"), document);
        indexWriter.close();
    }

}
